/*
 * comtradewriter.cpp
 *
 *  Created on: 2019年11月14日
 *      Author: turne
 */

#include <dm/app/comtradewriter.hpp>

#include <dm/os/log/logger.hpp>
#include <dm/datetime.hpp>
#include <dm/bits.hpp>
#include <string>

namespace dm{
namespace app{

static const char* logModule = "CComtradeWriter.app.dm";

using namespace std;

static void outputTsAscii( ostream& ostr,const dm::CTimeStamp& ts ){
	dm::CDateTime dt(ts);
	float s = ts.useconds()*0.000001;
	s += dt.sec();

	char buf[48];//dd/mm/yyyy,hh:mm:ss.000000
	sprintf(buf,"%02d/%02d/%04d,%02d:%02d:%02.6f",dt.day(),dt.month(),dt.year(),dt.hour(),dt.minute(),s);

	ostr <<buf;
}

CComtradeWriter::CComtradeWriter():CComtradeFiles(),m_index(0){
	m_revYear = 1999;
	log().debug(THISMODULE "创建对象");
}

CComtradeWriter::~CComtradeWriter(){
	if( m_ostr.is_open() ){
		log().debug(THISMODULE "自动关闭文件");
		m_ostr.close();
	}else{
		log().debug(THISMODULE "销毁对象");
	}
}

void CComtradeWriter::setStationName( const char* s ){
	dm::string::CStringRef(s).dumpAutoMalloc(&m_stationName);
}

void CComtradeWriter::setRecDevId( const char* s ){
	dm::string::CStringRef(s).dumpAutoMalloc(&m_recDevId);
}

void CComtradeWriter::setNetFreq( const float& f ){
	m_if = f;
}

void CComtradeWriter::clearRates(){
	m_rates.clear();
}

void CComtradeWriter::addRate( const CRate& rate ){
	m_rates.push_back(rate);
}

void CComtradeWriter::setTsStart( const dm::CTimeStamp& ts ){
	m_tsStart = ts;
}

void CComtradeWriter::setTsTrig( const dm::CTimeStamp& ts ){
	m_tsTrig = ts;
}

void CComtradeWriter::setFt( const EFormat& ft ){
	m_ft = ft;
}

void CComtradeWriter::setTimeMult( const float& f ){
	m_timeMult = f;
}

void CComtradeWriter::clearMeasures(){
	m_measures.clear();
}

void CComtradeWriter::addMeasureInfo( const CMeasureInfo& m ){
	m_measures.push_back(m);
}

void CComtradeWriter::clearStatus(){
	m_status.clear();
}

void CComtradeWriter::addStatusInfo( const CStatusInfo& s ){
	m_status.push_back(s);
}

void CComtradeWriter::reset(){
	if( m_ostr.is_open() )
		m_ostr.close();
}

/**
 * 开始输出数据
 * 产生cfg文件，数据文件
 * 接着应该调用append()函数添加数据
 * @return
 */
bool CComtradeWriter::dump(){
	if( m_ostr.is_open() ){
		log().info(THISMODULE "文件已经打开");
		m_ostr.close();
	}

	if( name()==NULL ){
		log().warnning(THISMODULE "未设置名称");
		return false;
	}

	std::string file = name();
	file += ".cfg";

	if( dir() ){
		if( dm::string::CStringRef(dir()).isEndWith("/\\") )
			file = dir() + file;
		else{
			file = '/' + file;
			file = dir() + file;
		}
	}

	// 创建配置文件
	ofstream ostr;
	ostr.open(file.c_str(),ostream::trunc|ostream::out);
	if( !ostr.is_open() ){
		log().warnning(THISMODULE "创建配置文件%s失败",file.c_str());
		return false;
	}

	if( stationName() )
		ostr<<stationName();
	ostr <<',';
	if( recDevId() )
		ostr << recDevId();
	ostr <<','<<revYear()<<"\r\n";

	ostr <<measureCount()+statusCount()<<','
			<<measureCount()<<"A,"
			<<statusCount()<<"D\r\n";

	for( unsigned int i=0;i<measureCount();++i ){
		ostr <<i+1<<',';
		const CMeasureInfo& m = measure(i);
		if( m.chId() )
			ostr <<m.chId();
		ostr <<',';

		if( m.ph() )
			ostr <<m.ph();
		ostr <<',';

		if( m.ccbm() )
			ostr <<m.ccbm();
		ostr <<',';

		if( m.uu() )
			ostr <<m.uu();
		ostr <<',';

		ostr <<m.a()<<','<<m.b()<<',';
		ostr <<m.skew();
		ostr <<',';

		ostr <<m.min()<<','<<m.max()<<','<<m.primary()<<','<<m.secondary()<<','<<m.ps()<<"\r\n";
	}

	for( unsigned int i=0;i<statusCount();++i ){
		ostr <<i+1<<',';

		const CStatusInfo& s = status(i);
		if( s.chId() )
			ostr <<s.chId();
		ostr <<',';

		if( s.ph() )
			ostr <<s.ph();
		ostr <<',';

		if( s.ccbm() )
			ostr <<s.ccbm();
		ostr <<',';

		ostr <<(s.y()?1:0)<<"\r\n";
	}

	if( netFreq()!=0 )
		ostr <<netFreq();
	ostr <<"\r\n";

	ostr <<ratesCount()<<"\r\n";
	for( unsigned int i=0;i<ratesCount();++i ){
		const CRate& r = rate(i);
		ostr <<r.samp()<<','<<r.endSamp()<<"\r\n";
	}

	outputTsAscii(ostr,tsStart());
	ostr <<"\r\n";

	outputTsAscii(ostr,tsTrig());
	ostr <<"\r\n";

	if( ft()==FormatBinary )
		ostr <<"BINARY"<<"\r\n";
	else
		ostr <<"ASCII"<<"\r\n";

	ostr <<timeMult()<<"\r\n";

	ostr.close();

	// 创建数据文件
	file = name();
	file += ".dat";
	if( dir() ){
		if( !dm::string::CStringRef(dir()).isEndWith("/\\") )
			file = '/' + file;
		file = dir() + file;
	}

	if( ft()==FormatBinary )
		m_ostr.open(file.c_str(),ofstream::trunc|ofstream::out|ofstream::binary);
	else
		m_ostr.open(file.c_str(),ofstream::trunc|ofstream::out);

	if( !m_ostr.is_open() ){
		log().warnning(THISMODULE "不能创建数据文件%s",file.c_str());
		return false;
	}

	m_index = 0;

	return true;
}


template<typename T>
static inline void outputBinary( ostream& ostr,const T& v ){
	ostr.write((const char*)&v,sizeof(v));
}

bool CComtradeWriter::append( const measure_t* measures,const unsigned int& measureSize,const status_t* status,const unsigned int& statusSize,const dm::CTimeStamp* ts ){
	if( !m_ostr.is_open() ){
		log().info(THISMODULE "文件未打开");
		return false;
	}

	if( measureSize!=measureCount() ){
		log().info(THISMODULE "测量量数量%d不一致%d",measureSize,measureCount());
		return false;
	}

	if( statusSize!=statusCount() ){
		log().info(THISMODULE "状态量数量%d不一致%d",statusSize,statusCount());
		return false;
	}

	++m_index;

	if( ft()==FormatBinary ){
		outputBinary(m_ostr,m_index);

		dm::uint32 t = 0xFFFFFFFF;
		if( ts )
			t = ts->useconds();

		outputBinary(m_ostr,t);

		for( unsigned int i=0;i<measureSize;++i )
			outputBinary(m_ostr,measures[i]);

		dm::uint16 b = 0;
		for( unsigned int i=0;i<statusSize;++i ){
			if( status[i] )
				dm::bit_set(b,i%16);
			if( (i%16)==15 ){
				outputBinary(m_ostr,b);
				b = 0;
			}
		}

		if( statusSize>0 && 15!=(statusSize%16) )
			outputBinary(m_ostr,b);
	}else if( ft()==FormatAscii ){
		m_ostr <<m_index<<',';

		// 时标后不用加‘,’
		if( ts )
			m_ostr <<(m_tsStart.escapeUSecs(*ts)/m_timeMult);

		for( unsigned int i=0;i<measureSize;++i )
			m_ostr <<','<<measures[i];

		for( unsigned int i=1;i<statusSize;++i )
			m_ostr <<','<<(status[i]?1:0);
		m_ostr <<"\r\n";
	}else{
		log().error(THISMODULE "未知数据格式%d",ft());
		return false;
	}

	if( m_index>=rows() ){
		log().info(THISMODULE "录波完成");
		m_ostr.close();
	}

	return true;
}

}
}
